// Copyright (c) 2008-2010, Arne Claus
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 
// following conditions are met:
//
// - Redistributions of source code must retain the above copyright notice, this list of conditions and the following 
//   disclaimer.
// - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following 
//   disclaimer in the documentation and/or other materials provided with the distribution.
// - Neither the name Arne Claus nor the names of any contributors may be used to endorse or promote products
//   derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef __INCLUDED_CRL_CAMERA_H_
#define __INCLUDED_CRL_CAMERA_H_

#include "CRL_Defines.h"
#include "CBL_Tuple.h"
#include "CBL_Matrix.h"

CB_SUBNAMESPACE_START(RenderLib)

class CCamera
{
public:
	
	enum EMatrixStyle
	{
		OpenGL,
		OpenGLOrtho,
		DirectX,
		DirectXOrtho
	};
	
public:
	
	CCamera();
	CCamera(EMatrixStyle _MatrixStyle);	
	CCamera(EMatrixStyle _MatrixStyle, float _Fov, float _Near, float _Far);	
	CCamera(EMatrixStyle _MatrixStyle, float _Left, float _Right, float _Top, float _Bottom, float _Near, float _Far);
	
	virtual ~CCamera() {}
	
public:
	
	// Any "set" function will require an "UpdateMatrices" afterwards
	
	void SetMatrixStyle(EMatrixStyle _MatrixStyle)					{ m_MatrixStyle = _MatrixStyle; }
	
	void SetPosition(const Math::Float3& _rPosition)				{ m_Position = _rPosition; }
	
	void SetNormalizedDirection(const Math::Float3& _rDirection)	{ m_Direction = _rDirection; }
	void SetDirectionAndNormalize(const Math::Float3& _rDirection)	{ m_Direction = Math::Normalize(_rDirection); }
	
	void SetUpVector(const Math::Float3& _rUpVector)				{ m_UpVector = _rUpVector; }
	
	void SetFov(float _Degrees)										{ SetFov(_Degrees, _Degrees); }
	void SetFov(float _DegreesX, float _DegreesY);
	
	void SetPlane(float _Left, float _Right, float _Top, float _Bottom);
	void SetFrustum(float _Left, float _Right, float _Top, float _Bottom, float _Near, float _Far);
	
	void SetNear(float _Near);
	void SetFar(float _Far);
		
public:
	
	const Math::Float3& GetPosition() const		{ return m_Position; }
	const Math::Float3& GetDirection() const	{ return m_Direction; }
	const Math::Float3& GetUpVector() const		{ return m_UpVector; }
	
	float GetFovX() const						{ return m_FovX; }
	float GetFovY() const						{ return m_FovY; }
	
	float GetLeft() const						{ return m_Left; }
	float GetRight() const						{ return m_Right; }
	float GetTop() const						{ return m_Top; }
	float GetBottom() const						{ return m_Bottom; }
	
	float GetNear() const						{ return m_Near; }
	float GetFar() const						{ return m_Far; }
	
public:
	
	void UpdateMatrices();

	const Math::Float4x4& GetViewMatrix() const				{ return m_View; }
	const Math::Float4x4& GetProjectionMatrix() const		{ return m_Projection; }
	const Math::Float4x4& GetViewProjectionMatrix() const	{ return m_ViewProjection; }	
	
protected:
	
	Math::Float4x4 GenerateViewMatrix() const;
	Math::Float4x4 GenerateProjectionMatrix() const;
	
protected:
	
	EMatrixStyle m_MatrixStyle;
	
	Math::Float4x4 m_View;
	Math::Float4x4 m_Projection;
	Math::Float4x4 m_ViewProjection;
	
	Math::Float3 m_Position;
	Math::Float3 m_Direction;
	Math::Float3 m_UpVector;
	
	float m_FovX;
	float m_FovY;
	
	float m_Left;
	float m_Right;
	float m_Top;
	float m_Bottom;
	
	float m_Near;
	float m_Far;
};


CB_SUBNAMESPACE_END

#endif